import 'package:built_collection/built_collection.dart';
import 'package:mobile_app.core/core/domain/entities/learning_content/collection_list_item/collection_list_item.dart';
import 'package:mobile_app.core/core/domain/entities/learning_content/lexical_item/lexical_item.dart';
import 'package:mobile_app.home.core/core/domain/helpers/is_collection_selection_effective/helper.dart';

abstract class GetLearnableUnspecifiedLexicalItemIds {
  BuiltSet<String> call({
    required BuiltList<CollectionListItem> collectionListItems,
    required BuiltMap<String, LexicalItem> lexicalItemMap,
    required BuiltSet<String> permittedCollectionListItemIds,
    required BuiltSet<String> permittedLexicalItemIds,
  });
}

class GetLearnableUnspecifiedLexicalItemIdsImpl implements GetLearnableUnspecifiedLexicalItemIds {
  const GetLearnableUnspecifiedLexicalItemIdsImpl({
    required IsCollectionSelectionEffective isCollectionSelectionEffective,
  }) : _isCollectionSelectionEffective = isCollectionSelectionEffective;

  final IsCollectionSelectionEffective _isCollectionSelectionEffective;

  @override
  BuiltSet<String> call({
    required BuiltList<CollectionListItem> collectionListItems,
    required BuiltMap<String, LexicalItem> lexicalItemMap,
    required BuiltSet<String> permittedCollectionListItemIds,
    required BuiltSet<String> permittedLexicalItemIds,
  }) {
    final learnableUnspecifiedLexicalItemIds = <String>{};

    for (final collectionListItem in collectionListItems) {
      switch (collectionListItem) {
        case Collection():
          final collection = collectionListItem;

          final collectionLearnableUnspecifiedLexicalItemIds =
              _getCollectionLearnableUnspecifiedLexicalItemIds(
            collection: collection,
            permittedCollectionListItemIds: permittedCollectionListItemIds,
            permittedLexicalItemIds: permittedLexicalItemIds,
            lexicalItemMap: lexicalItemMap,
          );

          learnableUnspecifiedLexicalItemIds.addAll(collectionLearnableUnspecifiedLexicalItemIds);

        case CollectionFolder():
          final collectionFolder = collectionListItem;

          for (final collection in collectionFolder.collections) {
            final collectionLearnableUnspecifiedLexicalItemIds =
                _getCollectionLearnableUnspecifiedLexicalItemIds(
              collection: collection,
              permittedCollectionListItemIds: permittedCollectionListItemIds,
              permittedLexicalItemIds: permittedLexicalItemIds,
              lexicalItemMap: lexicalItemMap,
            );

            learnableUnspecifiedLexicalItemIds.addAll(collectionLearnableUnspecifiedLexicalItemIds);
          }
      }
    }

    return learnableUnspecifiedLexicalItemIds.build();
  }

  Iterable<String> _getCollectionLearnableUnspecifiedLexicalItemIds({
    required Collection collection,
    required BuiltSet<String> permittedCollectionListItemIds,
    required BuiltSet<String> permittedLexicalItemIds,
    required BuiltMap<String, LexicalItem> lexicalItemMap,
  }) {
    final collectionPermitted = permittedCollectionListItemIds.contains(collection.id);

    final collectionSelectionEffective = _isCollectionSelectionEffective(
      collection: collection,
      collectionPermitted: collectionPermitted,
    );

    if (!collectionSelectionEffective) {
      return const {};
    }

    final permittedCollectionLexicalItemIds = collection.lexicalItemIds.where((lexicalItemId) {
      return permittedLexicalItemIds.contains(lexicalItemId);
    });

    return permittedCollectionLexicalItemIds.where((lexicalItemId) {
      final lexicalItem = lexicalItemMap[lexicalItemId]!;
      return lexicalItem.isUnspecified && !lexicalItem.excluded;
    });
  }
}
